#include <jni.h>

#include <stddef.h>

#define LOG_TAG "NVRomData"

#include <android/log.h>
#include <assert.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

#define ALOGI(fmt, args...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, fmt, ##args)
#define ALOGD(fmt, args...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, fmt, ##args)
#define ALOGW(fmt, args...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, fmt, ##args)
#define ALOGE(fmt, args...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, fmt, ##args)

static const char* JAVA_CLASS_PATH_NAME = "com/htfyun/nvrom/NVRomOperation";
static const char* JAVA_CLASS_PATH_NAME_INTEGER_INFO = "com/htfyun/nvrom/NVRomIntegerInfo";
static const char* JAVA_CLASS_PATH_NAME_STRING_INFO = "com/htfyun/nvrom/NVRomStringInfo";

/*
 * read me
 * 1. 我们使用 key-value 形式存储数据。key 是 String 格式。
 * 2. 我们使用 0 ~ 1M 空间来储存 value 是 int 型的数据。
 * 3. 我们使用 1M ~ 6M 空间来储存 value 是 String 型的数据。
 */
#define VNROM_DEV_PRIVDATA_PATH  "/dev/block/by-name/privdata"

#define VNROM_KEY_INTEGER_ADDR_START   (0)
#define VNROM_KEY_STRING_ADDR_START    ((1 * 1024 * 1024))
#define USE_DEFINED_STRING_ADDR 1 //如果是1, 就是用VNROM_KEY_INTEGER_ADDR_OFFSET和VNROM_KEY_STRING_ADDR_OFFSET, 否则就是根据大小计算出来的.

#define VNROM_KEY_INTEGER_COUNT (250*8) //一个key-int 的 item 不到100 byte, 所以分配的空间足够了.

#define VNROM_KEY_STRING_COUNT  (250*8) // 一个 key-string 的 item 不到1200 byte, 所以分配的空间足够了

/////////////////////////////////////////////////////////////////////////////
//由于不清楚 VNROM 里面的默认值是什么。 所以用这个ID来标识 我们设置 了该 item
#define VNROM_ITEM_SET_ID       0xA5A5F11F
#define VNROM_KEY_SIZE          63
#define VNROM_VALUE_STRING_SIZE 1023

//由于在不同的编译器上, sizeof(struct timeval) 的大小不一样, 导致块大小不同, 从而影响读写块的一致性;
// 在 ndk 编译的 sizeof(struct timeval) = 8, 而在 android 64bit 上编译的是 16;
//所以我们用union来固定其大小, 当然他必须大于原来的struct item大小
#define UNION_SIZE_MARGIN 50 // 在 VNROM_KEY_SIZE(+VNROM_VALUE_STRING_SIZE) 基础上增加50个字节就足够了.


//计算a以size为倍数的上下界数:
//http://blog.sina.com.cn/s/blog_60692ff60100fhmg.html
#define ALIGNMENT_DOWN(a, size) (a & (~(size-1)) )
#define ALIGNMENT_UP(a, size)   ((a+size-1) & (~ (size-1)))


struct key_index_t {
     char key[VNROM_KEY_SIZE + 1];//with '\0'
     int index;
};

struct search_index_t {
    //用每一个char来标识该index是否有被占用, 1标识占用, 0 标识没有占用. 本来想用bit来标识. 不过觉得bit太麻烦了.
    unsigned char index_int[VNROM_KEY_INTEGER_COUNT];
    unsigned char index_string[VNROM_KEY_STRING_COUNT];
    int key_int_addr_start;
    int key_string_addr_start;

    struct key_index_t key_index_int[VNROM_KEY_INTEGER_COUNT];
    struct key_index_t key_index_string[VNROM_KEY_STRING_COUNT];
};


struct item_integer {
    union {
        char block_size[VNROM_KEY_SIZE + UNION_SIZE_MARGIN];

        struct {
            unsigned int set_id;
            char key[VNROM_KEY_SIZE + 1];//with '\0'
            int value;
            int offset_index;
            struct timeval set_time;
        };
    };

};

struct item_string {

    union {
        char block_size[VNROM_KEY_SIZE + VNROM_VALUE_STRING_SIZE +  UNION_SIZE_MARGIN];

        struct {
            unsigned int set_id;
            char key[VNROM_KEY_SIZE + 1]; //with '\0'
            char value[VNROM_VALUE_STRING_SIZE + 1]; //with '\0'
            int offset_index;
            struct timeval set_time;
        };
    };

};

#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))

struct search_index_t g_search_index;


// return the readed length, <=0 -- error.
static int nvrom_read_priv_block_dev(void* buf, int size, int offset )
{
    int ret;
    const char* fp = VNROM_DEV_PRIVDATA_PATH;
    int fd = open(fp, O_RDONLY, 0);
    if(fd < 0){
        /* got log:
         * open "/dev/block/platform/ff0f0000.dwmmc/by-name/privdata" fail.Permission denied.
        */
        ALOGE("open %s for read fail.%s\n",fp, strerror(errno) );
        return fd;
    }

    memset(buf, 0, size);
    lseek(fd, offset, SEEK_SET);
    ret = read(fd, buf, size);
    if( ret <= 0 ){
        ALOGE("read %s fail.%s\n",fp, strerror(errno) );
        ret = -1;
    }
    close(fd);
    if( ret != size ){
        ALOGW("Read %s Error,size=%d,ret=%d" , fp, size, ret);
    }
    return ret;
}

// return the writed length, <=0 -- error.
static int nvrom_write_priv_block_dev(void* buf, int size, int offset )
{
    int ret;
    const char* fp = VNROM_DEV_PRIVDATA_PATH;
    int fd = open(fp, O_RDWR/*O_WRONLY*/, 0); //O_RDWR
    if(fd < 0){
        // open "/dev/block/platform/ff0f0000.dwmmc/by-name/privdata" fail.Permission denied
        ALOGE("open %s for write fail.%s\n",fp, strerror(errno) );
        return fd;
    }
    lseek(fd, offset, SEEK_SET);
    ret = write(fd, buf, size);

    if( ret <= 0 ){
        ALOGE("write %s fail.%s\n",fp, strerror(errno) );
        ret = -1;
    }
    fsync(fd);
    close(fd);
    if( size != ret ){
        ALOGW("write %s error.size=%d,ret=%d\n",fp, size, ret);
    }
    return ret;
}

static int initSearchIndex(void)
{

    struct item_integer * int_item = NULL;

    struct item_string * string_item = NULL;

    int ret = 0;
    int index;
    struct search_index_t * search_index = &g_search_index;

    ALOGE("initSearchIndex start, sizeof(struct timeval) = %d", (int)sizeof(struct timeval));

    search_index->key_int_addr_start = VNROM_KEY_INTEGER_ADDR_START;
#if USE_DEFINED_STRING_ADDR
    search_index->key_string_addr_start = VNROM_KEY_STRING_ADDR_START;
#else
    search_index->key_string_addr_start = search_index->key_int_addr_start + (VNROM_KEY_INTEGER_COUNT * sizeof(struct item_integer));
#endif

    int_item = (struct item_integer *) calloc(1, sizeof(struct item_integer));

    if (!int_item) {
        ALOGE("alloc item_integer error. err = %s\n", strerror(errno));
        return -ENOMEM;
    }
    for(index = 0; index < VNROM_KEY_INTEGER_COUNT; index++) {
        ret = nvrom_read_priv_block_dev((void *) int_item,
                        1 * sizeof(struct item_integer),
                        (index * sizeof(struct item_integer)) + search_index->key_int_addr_start);
        if (ret != 1 * (int)sizeof(struct item_integer)) {
            ALOGW("read priv block error. ret=%d\n", ret);
            continue;
        }

        if (int_item->set_id != VNROM_ITEM_SET_ID || int_item->offset_index < 0) {
            search_index->index_int[index] = 0;
            search_index->key_index_int[index].index = -1;
            search_index->key_index_int[index].key[0] = '\n';
        } else {
            search_index->index_int[index] = 1;
            search_index->key_index_int[index].index = index;
            strcpy(search_index->key_index_int[index].key, int_item->key);
        }
    }


    if (int_item) {
        free(int_item);
        int_item = NULL;
    }

    string_item = (struct item_string *) calloc(1, sizeof(struct item_string));
    if (!string_item) {
       ALOGE("alloc item_string error. err = %s\n", strerror(errno));
       return -ENOMEM;
    }

    for(index = 0; index < VNROM_KEY_STRING_COUNT; index++) {
        ret = nvrom_read_priv_block_dev((void *) string_item,
                        1 * sizeof(struct item_string),
                        (index * sizeof(struct item_string)) + search_index->key_string_addr_start);

        if (ret != 1 * (int)sizeof(struct item_string)) {
            ALOGW("read priv block error. ret=%d\n", ret);
            continue;
        }

        if (string_item->set_id != VNROM_ITEM_SET_ID || string_item->offset_index < 0 ) {
            search_index->index_string[index] = 0;
            search_index->key_index_string[index].index = -1;
            search_index->key_index_string[index].key[0] = '\0';
        } else {
            search_index->index_string[index] = 1;
            search_index->key_index_string[index].index = index;
            strcpy(search_index->key_index_string[index].key, string_item->key);
        }
    }

    if (string_item) {
        free(string_item);
        string_item = NULL;
    }
    return 0;
}

static bool setKeyValueInteger(const char * key, int value)
{
    int ret;
    struct search_index_t *search_index = &g_search_index;
    unsigned int index;
    int found_index = -1;
    struct item_integer item;

    memset(&item, 0, sizeof(item));

    for (index = 0; index < ARRAY_SIZE(search_index->key_index_int); index++) {
        if (!strcmp(key, search_index->key_index_int[index].key)) {
            found_index = index;
            break;
        }
    }

    if (found_index < 0) {
        //new key-value
        for (index = 0; index < ARRAY_SIZE(search_index->index_int); index++) {
            if (!search_index->index_int[index]) {
                found_index = index;
                break;
            }
        }
    }
    if (found_index < 0) {
        ALOGW("int item is full. item count(%d) is small.\n", VNROM_KEY_INTEGER_COUNT);
        return false;
    }


    //set key-value
    item.set_id = VNROM_ITEM_SET_ID;
    item.offset_index = found_index;
    item.value = value;
    if (strlen(key) >= sizeof(item.key)) {
        memcpy(item.key, key, sizeof(item.key) - 1);
        item.key[sizeof(item.key) - 1] = '\0';
    } else {
        strcpy(item.key,  key);
    }
    gettimeofday(&item.set_time, NULL);//time to set the item

    ALOGI("set integer key-value = %s: 0x%x(%d), index = %d", key, value, value, found_index);

    ret = nvrom_write_priv_block_dev((void *) &item, sizeof(item),
                                  found_index * sizeof(item) + search_index->key_int_addr_start);

    if (ret != sizeof(item)) {

        ALOGE("NVROM failed to set key-value = %s:0x%x", key, value);

        return false;
    }


    //update search_index
   search_index->index_int[found_index] = 1;
   search_index->key_index_int[found_index].index = found_index;
   strcpy(search_index->key_index_int[found_index].key, item.key);

    return true;
}

static int getKeyValueInteger(const char * key, int default_value)
{
    int ret;
    struct search_index_t *search_index = &g_search_index;
    unsigned int index;
    int found_index = -1;
    struct item_integer item;
    for (index = 0; index < ARRAY_SIZE(search_index->key_index_int); index++) {
        if (!strcmp(key, search_index->key_index_int[index].key)) {
            found_index = index;
            break;
        }
    }

    if (found_index < 0) {
        ALOGW("int item key(%s) not found.\n", key);
        return default_value;
    }


    ret = nvrom_read_priv_block_dev((void *) &item, sizeof(item),
                        found_index * sizeof(item) + search_index->key_int_addr_start);

    if (ret != sizeof(item)) {
        ALOGE("%s: read priv block error. ret=%d\n", __FUNCTION__, ret);
        return default_value;
    }

    return item.value;

}


static bool removeKeyValueInteger(const char * key)
{
    int ret;
    struct search_index_t *search_index = &g_search_index;
    unsigned int index;
    int found_index = -1;
    struct item_integer item;
    for (index = 0; index < ARRAY_SIZE(search_index->key_index_int); index++) {
        if (!strcmp(key, search_index->key_index_int[index].key)) {
            found_index = index;
            break;
        }
    }

    if (found_index < 0) {
        ALOGW("Cant remove, int item key(%s) not found.\n", key);
        return false;
    }

    //remove search_index
    search_index->index_int[found_index] = 0;
    search_index->key_index_int[found_index].index = -1;
    search_index->key_index_int[found_index].key[0] = '\0';

    //clear item
    memset(&item, 0, sizeof(item));
    item.offset_index = -1;

    ret = nvrom_write_priv_block_dev((void *)&item, sizeof(item),
                                  found_index * sizeof(item) + search_index->key_int_addr_start);

    if (ret != sizeof(item)) {

        ALOGE("Failed to remove integer key = %s.", key);

        return false;
    }

    return true;

}



static jobjectArray getAllInteger(JNIEnv* env, jclass clazz, jint startOffset, jint _count)
{
    struct search_index_t *search_index = &g_search_index;
    struct item_integer item;
    int valid_count = 0;
    int ret, i;
    unsigned int index;
    int array_index = 0;
    int count = _count;

    unsigned int valid_index[ARRAY_SIZE(search_index->index_int)];

    for (index = 0; index < ARRAY_SIZE(search_index->index_int); index++) {
        if (search_index->index_int[index]) {
            valid_index[valid_count++] = index;
        }
    }

    if (startOffset > valid_count) {
        ALOGE("getAllInteger error, startOffset(%d) is bigger than valid_count(%d).", startOffset, valid_count);
        return NULL;
    }

    if (count > valid_count) {
        ALOGW("getAllInteger warning, count(%d) is bigger than valid_count(%d). so get count is (valid_count)(%d)", count, valid_count, (valid_count ));
        count = valid_count;
    }

    if (startOffset + count > valid_count) {
        ALOGW("getAllInteger warning, (startOffset + count)(%d) is bigger than valid_count(%d). so get count is (valid_count - startOffset)(%d)", startOffset + count, valid_count, (valid_count - startOffset));
        count = (valid_count - startOffset);
    }

    ALOGI("getAllInteger: get count(%d) from startOffset(%d)", count, startOffset);

    jclass infoClass = env->FindClass(JAVA_CLASS_PATH_NAME_INTEGER_INFO);
    jobjectArray myArray = (jobjectArray)env->NewObjectArray(count, infoClass, NULL);;

    for(i = 0; i < count; i++) {
        index = valid_index[i + startOffset];
        ret = nvrom_read_priv_block_dev((void *) &item, sizeof(item),
                                index * sizeof(item) + search_index->key_int_addr_start);

        if (ret != sizeof(item)) {
            ALOGE("%s: read priv block error. ret=%d\n", __FUNCTION__, ret);
            continue;
        }

        jmethodID init = env->GetMethodID(infoClass, "<init>","()V");
        jobject jInfo = env->NewObject(infoClass, init);

        env->SetObjectArrayElement(myArray, array_index++, jInfo);

        jfieldID  jID_key = env->GetFieldID(infoClass, "key", "Ljava/lang/String;");
        jfieldID  jID_value = env->GetFieldID(infoClass, "value", "I");
        jfieldID  jID_offset_index = env->GetFieldID(infoClass, "offset_index", "I");
        jfieldID  jID_time_s = env->GetFieldID(infoClass, "set_time_s", "J");
        jfieldID  jID_time_us = env->GetFieldID(infoClass, "set_time_us", "J");

        jstring jstr = (jstring)(env->NewStringUTF(item.key));
        env->SetObjectField(jInfo, jID_key, jstr);
        env->SetIntField(jInfo, jID_value, item.value);
        env->SetIntField(jInfo, jID_offset_index, item.offset_index);
        env->SetLongField(jInfo, jID_time_s, (jlong)(item.set_time.tv_sec));
        env->SetLongField(jInfo, jID_time_us, (jlong)(item.set_time.tv_usec));

        env->DeleteLocalRef(jstr);
        env->DeleteLocalRef(jInfo);
    }

    return myArray;
}

static jint getCountOfAllInteger(void)
{
     struct search_index_t * search_index = &g_search_index;
     int valid_count = 0;
     unsigned int index;

     for (index = 0; index < ARRAY_SIZE(search_index->index_int); index++) {
         if (search_index->index_int[index]) {
             valid_count++;
         }
     }

     return valid_count;
}

static bool setKeyValueString(const char * key, const char * value)
{
    int ret;
    struct search_index_t *search_index = &g_search_index;
    unsigned int index;
    int found_index = -1;
    struct item_string item;

    memset(&item, 0, sizeof(item));

    for (index = 0; index < ARRAY_SIZE(search_index->key_index_string); index++) {
        if (!strcmp(search_index->key_index_string[index].key, key)) {
            found_index = index;
            break;
        }
    }
    if (found_index < 0) {
        //new key-value
        for (index = 0; index < ARRAY_SIZE(search_index->index_string); ++index) {
            if (!search_index->index_string[index]) {
                found_index = index;
                break;

            }
        }
    }

    if (found_index < 0) {
        ALOGW("string item is full. item count(%d) is small.\n", VNROM_KEY_STRING_COUNT);
        return false;
    }

    //set key-value
    item.set_id = VNROM_ITEM_SET_ID;
    item.offset_index = found_index;
    if (strlen(key) >= sizeof(item.key)) {
        memcpy(item.key, key, sizeof(item.key) - 1);
        item.key[sizeof(item.key) - 1] = '\0';
    } else {
        strcpy(item.key, key);
    }
    if (strlen(value) >= sizeof(item.value)) {
        memcpy(item.value, value, sizeof(item.value) - 1);
        item.value[sizeof(item.value) - 1] ='\0';
    } else {
        strcpy(item.value, value);
    }
    gettimeofday(&item.set_time, NULL);//time to rw the item

    ALOGI("set string key-value = %s : %s, index = %d", key, value, found_index);

    ret = nvrom_write_priv_block_dev((void *) &item, sizeof(item),
                        found_index * sizeof(item) + search_index->key_string_addr_start);

    if (ret != sizeof(item)) {
         ALOGE("NVROM failed to set key-value = %s:%s", key, value);
        return false;
    }


    //update search index
    search_index->index_string[found_index] = 1;
    search_index->key_index_string[found_index].index = found_index;
    strcpy(search_index->key_index_string[found_index].key, item.key);

    return true;

}


static bool getKeyValueString(const char * key, char * str)
{
    struct search_index_t * search_index = &g_search_index;
    struct item_string item;
    int found_index = -1;
    unsigned int index;
    int ret;

    for (index = 0; index < ARRAY_SIZE(search_index->key_index_string); ++index) {
        if (!strcmp(search_index->key_index_string[index].key, key)) {
            found_index = index;
        }
    }

    if (found_index < 0) {
        ALOGW("string item key(%s) not found.\n", key);
        return false;
    }

    ret = nvrom_read_priv_block_dev((void *) &item, sizeof(item),
                    found_index * sizeof(item) + search_index->key_string_addr_start);

    if (ret != sizeof(item)) {
        ALOGE("%s: read priv block error. ret=%d\n", __FUNCTION__, ret);
        return false;
    }

    strcpy(str, item.value);

    return true;
}

static bool removeKeyValueString(const char * key)
{
    struct search_index_t *search_index = &g_search_index;
    struct item_string item;
    unsigned int index;
    int found_index = -1;
    int ret;

    for(index = 0; index < ARRAY_SIZE(search_index->key_index_string); index ++) {
        if (!strcmp(search_index->key_index_string[index].key, key)) {
            found_index = index;
            break;
        }
    }

    if (found_index < 0) {
        ALOGW("Cant remove, string item key(%s) not found.\n", key);
        return false;
    }


    //clear search index
    search_index->index_string[found_index] = 0;
    search_index->key_index_string[found_index].index = -1;
    search_index->key_index_string[found_index].key[0] = '\0';

    //clear item;
    memset(&item, 0, sizeof(item));
    item.offset_index = -1;

    ret = nvrom_write_priv_block_dev((void *)&item, sizeof(item),
                    found_index * sizeof(item) + search_index->key_string_addr_start);


    if (ret != sizeof(item)) {
        ALOGE("Failed to remove integer key = %s.", key);
        return false;
    }

    return true;
}


static jobjectArray getAllString(JNIEnv* env, jclass clazz, jint startOffset, jint _count)
{

    struct search_index_t * search_index = &g_search_index;
    struct item_string item;
    int valid_count = 0;
    int ret, i;
    int array_index = 0;
    unsigned int index;
    int count = _count;

    int valid_index[ARRAY_SIZE(search_index->index_string)];

    for (index = 0; index < ARRAY_SIZE(search_index->index_string); index++) {
        if (search_index->index_string[index]) {
            valid_index[valid_count++] = index;
        }
    }

    if (startOffset > valid_count) {
        ALOGE("getAllString error, startOffset(%d) is bigger than valid_count(%d).", startOffset, valid_count);
        return NULL;
    }

    if (count > valid_count) {
        ALOGW("getAllString warning, count(%d) is bigger than valid_count(%d). so get count is (valid_count)(%d)", count, valid_count, (valid_count ));
        count = valid_count;
    }

    if (startOffset + count > valid_count) {
        ALOGW("getAllString warning, (startOffset + count)(%d) is bigger than valid_count(%d). so get count is (valid_count - startOffset)(%d)", startOffset + count, valid_count, (valid_count - startOffset));
        count = (valid_count - startOffset);
    }

    ALOGI("getAllString: get count(%d) from startOffset(%d)", count, startOffset);

    jclass infoClass = env->FindClass(JAVA_CLASS_PATH_NAME_STRING_INFO);
    jobjectArray myArray = (jobjectArray)env->NewObjectArray(count, infoClass, NULL);

    for(i = 0; i < count; i++) {
        index = valid_index[i + startOffset];
        ret = nvrom_read_priv_block_dev((void *)&item, sizeof(item),
                            index * sizeof(item) + search_index->key_string_addr_start);

        if (ret != sizeof(item)) {
            ALOGE("%s: read priv block error. ret=%d\n", __FUNCTION__, ret);
            continue;
        }

        jmethodID init = env->GetMethodID(infoClass, "<init>","()V");
        jobject jInfo = env->NewObject(infoClass, init);

        env->SetObjectArrayElement(myArray, array_index++, jInfo);

        jfieldID  jID_key = env->GetFieldID(infoClass, "key", "Ljava/lang/String;");
        jfieldID  jID_value = env->GetFieldID(infoClass, "value", "Ljava/lang/String;");
        jfieldID  jID_offset_index = env->GetFieldID(infoClass, "offset_index", "I");
        jfieldID  jID_time_s = env->GetFieldID(infoClass, "set_time_s", "J");
        jfieldID  jID_time_us = env->GetFieldID(infoClass, "set_time_us", "J");

        jstring jstrKey = (jstring)(env->NewStringUTF(item.key));
        env->SetObjectField(jInfo, jID_key, jstrKey);
        jstring jstrValue = (jstring)(env->NewStringUTF(item.value));
        env->SetObjectField(jInfo, jID_value, jstrValue);
        env->SetIntField(jInfo, jID_offset_index, item.offset_index);
        env->SetLongField(jInfo, jID_time_s, (jlong)(item.set_time.tv_sec));
        env->SetLongField(jInfo, jID_time_us, (jlong)(item.set_time.tv_usec));

        env->DeleteLocalRef(jstrKey);
        env->DeleteLocalRef(jstrValue);
        env->DeleteLocalRef(jInfo);

    }

    return myArray;
}

static jint getCountOfAllString(void)
{
     struct search_index_t * search_index = &g_search_index;
     int valid_count = 0;
     unsigned int index;

     for (index = 0; index < ARRAY_SIZE(search_index->index_string); ++index) {
         if (search_index->index_string[index]) {
            valid_count ++;
         }
     }

     return valid_count;
}

/////////////////////////////////////////////////////////////////////////////

static jboolean setIntegerNVRom(JNIEnv* env, jclass clazz,
    jstring key, int value ) {
    bool result = false;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    if(c_key){
        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        result = setKeyValueInteger((const char *)c_key, value);
        (env)->ReleaseStringUTFChars(key, c_key );
    }

    return (jboolean)result;
}

static jint getIntegerNVRom(JNIEnv* env, jclass clazz,
    jstring key , jint defaultData ) {

    int result = defaultData;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    if(c_key){
        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        result = getKeyValueInteger((const char *)c_key, result);
        (env)->ReleaseStringUTFChars(key, c_key );
    }

    return result;
}

static jboolean removeIntegerNVRom(JNIEnv* env, jclass clazz, jstring key ) {

    bool result = false;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    if(c_key){
        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        result = removeKeyValueInteger((const char *)c_key);
        (env)->ReleaseStringUTFChars(key, c_key );
    }

    return (jboolean)result;
}

static jobjectArray getAllIntegerNVRom(JNIEnv* env, jclass clazz, jint startOffset, jint count)
{
    return getAllInteger(env, clazz, startOffset, count);
}

static jint getCountOfAllIntegerNVRom(JNIEnv* env, jclass clazz)
{
    return getCountOfAllInteger();
}


static jboolean setStringNVRom(JNIEnv* env, jclass clazz,
    jstring key, jstring content) {

    bool result = false;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    char *the_content = (char *) (env)->GetStringUTFChars(content,NULL);

    if(c_key && the_content){

        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        if (strlen(the_content) > VNROM_VALUE_STRING_SIZE) {
            c_key[VNROM_VALUE_STRING_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(the_content), VNROM_VALUE_STRING_SIZE, the_content);
        }
        result = setKeyValueString((const char *)c_key, (const char *)the_content);

        (env)->ReleaseStringUTFChars(key, c_key );
        (env)->ReleaseStringUTFChars( content, the_content );
    }

    return (jboolean)result;
}

static jstring getStringNVRom(JNIEnv* env, jclass clazz,
    jstring key) {

    char  str[VNROM_VALUE_STRING_SIZE + 1];
    bool ret = false;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    if(c_key){
        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        ret = getKeyValueString((const char *)c_key, str);
        (env)->ReleaseStringUTFChars(key, c_key );
    }
    if (
!ret) {
        return env->NewStringUTF("");
    }
    return env->NewStringUTF(str);
}

static jboolean removeStringNVRom(JNIEnv* env, jclass clazz,
        jstring key) {

    bool result = false;
    char *c_key = (char *) (env)->GetStringUTFChars(key, NULL);
    if(c_key){
        if (strlen(c_key) > VNROM_KEY_SIZE) {
            c_key[VNROM_KEY_SIZE] = '\0';
            ALOGE("WARNING: key size(%zu) is longer than %d. valid key is %s.", strlen(c_key), VNROM_KEY_SIZE, c_key);
        }
        result = removeKeyValueString((const char *)c_key);
        (env)->ReleaseStringUTFChars(key, c_key );
    }

    return (jboolean) result;
}

static jobjectArray getAllStringNVRom(JNIEnv* env, jclass clazz, jint startOffset, jint count)
{
    return getAllString(env, clazz, startOffset, count);
}

static jint getCountOfAllStringNVRom(JNIEnv* env, jclass clazz)
{
    return getCountOfAllString();
}

static JNINativeMethod method_table[] = {

	// key - integer
	{ "setIntegerNVRom", "(Ljava/lang/String;I)Z", (void*)setIntegerNVRom },
	{ "getIntegerNVRom", "(Ljava/lang/String;I)I", (void*)getIntegerNVRom },
	{ "removeIntegerNVRom", "(Ljava/lang/String;)Z", (void*)removeIntegerNVRom },
	{ "getAllIntegerNVRom", "(II)[Lcom/htfyun/nvrom/NVRomIntegerInfo;", (void*)getAllIntegerNVRom },
	{ "getCountOfAllIntegerNVRom", "()I", (void*)getCountOfAllIntegerNVRom },

	//key - string
	{ "getStringNVRom", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getStringNVRom },
	{ "setStringNVRom", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*) setStringNVRom },
	{ "removeStringNVRom", "(Ljava/lang/String;)Z", (void*)removeStringNVRom },
	{ "getAllStringNVRom", "(II)[Lcom/htfyun/nvrom/NVRomStringInfo;", (void*)getAllStringNVRom },
	{ "getCountOfAllStringNVRom", "()I", (void*)getCountOfAllStringNVRom },
};

//此函数通过调用JNI中 RegisterNatives 方法来注册我们的函数
static int registerNativeMethods(JNIEnv* env, const char* className,JNINativeMethod* getMethods,int methodsNum){
    jclass clazz;
    //找到声明native方法的类
    clazz = env->FindClass(className);
    if(clazz == NULL){
        return JNI_FALSE;
    }
   //注册函数 参数：java类 所要注册的函数数组 注册函数的个数
    if(env->RegisterNatives(clazz, getMethods, methodsNum) < 0){
        return JNI_FALSE;
    }

    initSearchIndex();

    return JNI_TRUE;
}
static int registerNatives(JNIEnv* env) {
	//指定类的路径，通过FindClass 方法来找到对应的类
	const char* className = JAVA_CLASS_PATH_NAME;
	return registerNativeMethods(env, className, method_table,
			sizeof(method_table) / sizeof(method_table[0]));
}
//回调函数 在这里面注册函数
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
    JNIEnv* env = NULL;
   //判断虚拟机状态是否有问题
    if(vm->GetEnv((void**)&env,JNI_VERSION_1_6)!= JNI_OK){
        return -1;
    }
    assert(env != NULL);
    //开始注册函数 registerNatives -》registerNativeMethods -》env->RegisterNatives
    if(!registerNatives(env)){
        return -1;
    }
    //返回jni 的版本
    return JNI_VERSION_1_6;
}
